using System;
using System.Collections;
using System.Data;

using LocalBoard.Domain;

namespace LocalBoard.Persistence.MockAccessor
{
	/// <summary>
	/// Summary description for MockMessageAccessor.
	/// </summary>
	public class MockMessageAccessor : IMessageAccessor, IMockAccessor
	{
		private int _oId = 0;
		private Hashtable _no = new Hashtable();
		private DataTable _messageTable = new DataTable("Message");
		private MockProfile_x_PollMessage _profile_x_pollMessage = MockProfile_x_PollMessage.Instance;

		public static readonly MockMessageAccessor Instance = 
			new MockMessageAccessor();

		private MockMessageAccessor()
		{
			_messageTable.Columns.Add("Id", typeof(int));
			_messageTable.Columns.Add("No", typeof(int));
			_messageTable.Columns.Add("Subject", typeof(string));
			_messageTable.Columns.Add("Body", typeof(string));
			_messageTable.Columns.Add("PostedByUserName", typeof(string));
			_messageTable.Columns.Add("PostedByUserId", typeof(string));
			_messageTable.Columns.Add("Hits", typeof(int));
			_messageTable.Columns.Add("CreateDate", typeof(DateTime));
			_messageTable.Columns.Add("MessageType", typeof(int));
			_messageTable.Columns.Add("Author_Id", typeof(int));
			_messageTable.Columns.Add("Board_Id", typeof(int));
			_messageTable.Columns.Add("Club_Id", typeof(int));
			_messageTable.Columns.Add("ReplyTo_Id", typeof(int));
			_messageTable.Columns.Add("UpdateDate", typeof(DateTime));
		}

		public void ResetDataTable()
		{
			_oId = 0;
			_messageTable.Clear();
			_no.Clear();
			_profile_x_pollMessage.ResetDataTable();
		}

		public void RemoveRows(int tableIndex, DataRow[] rows)
		{
			throw new NotImplementedException();
		}

		public DataRow[] ExecuteFilter(string filterExpression)
		{
			throw new NotImplementedException();
		}

		#region IMessageAccessor Members

		public ArrayList GetMessageListByBoardId(int boardId, int numberPerPage, int pageNo)
		{
			return GetMessageListByQuery(pageNo, numberPerPage, string.Format("Board_Id={0} and ReplyTo_Id=0", boardId));
		}

		public ArrayList GetMessageListByClubId(int clubId, int numberPerPage, int pageNo)
		{
			return GetMessageListByQuery(pageNo, numberPerPage, string.Format("Club_Id={0} and ReplyTo_Id=0", clubId));
		}

		public Message Get(int id)
		{
			DataRow[] result = _messageTable.Select(string.Format("Id={0}", id));
			if(result.Length > 0)
				return GetMessageFromResultRow(result[0]);
			else
				return null;
		}

		public ArrayList GetReplies(int id)
		{
			ArrayList replies = new ArrayList();
			foreach(DataRow row in _messageTable.Select(string.Format("ReplyTo_Id={0}", id)))
			{
				replies.Add(GetMessageFromResultRow(row));
			}
			return replies;
		}

		public int GetTotalRootMessageCountByBoardId(int boardId)
		{
			return _messageTable.Select(string.Format("Board_Id={0} and ReplyTo_Id=0", boardId)).Length;
		}

		public int GetTotalRootMessageCountByClubId(int clubId)
		{
			return _messageTable.Select(string.Format("Club_Id={0} and ReplyTo_Id=0", clubId)).Length;
		}

		public int Insert(Message message)
		{
			if(message == null)
				throw new ArgumentException("message");
			if(message.Author == null)
				throw new ArgumentException("message.Author");
			_oId++;
			DataRow newRow = _messageTable.NewRow();
			
			newRow["Id"] = _oId;
			newRow["No"] = 0;
			int counter = 1;
			if(message.ReplyToId == 0)
			{
				if(_no[message.BoardId] == null)
				{
					_no.Add(message.BoardId, counter);
				}
				else
				{
					counter = Convert.ToInt32(_no[message.BoardId]);
					_no[message.BoardId] = ++counter;
				}
				newRow["No"] = counter;
			}
			newRow["Subject"] = message.Subject;
			newRow["Body"] = message.Body;
			newRow["PostedByUserName"] = message.Author.UserName;
			newRow["PostedByUserId"] = message.Author.UserId;
			newRow["Hits"] = message.Hits;
			newRow["CreateDate"] = DateTime.Now;
			newRow["MessageType"] = Message.GetMessageTypeId(message);
			newRow["Author_Id"] = message.Author.Id;
			newRow["Board_Id"] = message.BoardId;
			newRow["Club_Id"] = message.ClubId;
			newRow["ReplyTo_Id"] = message.ReplyToId;

			_messageTable.Rows.Add(newRow);

			return _oId;
		}

		public void Update(Message message)
		{
			DataRow row = FindMessageDataRow(message.Id);
			if(row!=null)
			{
				row["Subject"] = message.Subject;
				row["Body"] = message.Body;
				row["UpdateDate"] = DateTime.Now;
				_messageTable.AcceptChanges();
			}
		}

		public void IncreaseHit(Message message)
		{
			DataRow row = FindMessageDataRow(message.Id);
			if(row!=null)
			{
				row["Hits"] = Convert.ToInt32(row["Hits"]) + 1;
				_messageTable.AcceptChanges();
			}
		}

		public void Delete(int id)
		{
			MockCommentAccessor commentAccessor = MockCommentAccessor.Instance;
			MockAttachmentAccessor attachmentAccessor = MockAttachmentAccessor.Instance;
			MockPollItemAccessor pollItemAccessor = MockPollItemAccessor.Instance;

			DataRow row = FindMessageDataRow(id);
			if(row != null)
			{
				foreach(Comment comment in commentAccessor.GetCommentListByMessageId(id))
				{
					commentAccessor.Delete(comment.Id);
				}
				foreach(Attachment attachment in attachmentAccessor.GetAttachmentListByMessageId(id))
				{
					attachmentAccessor.Delete(attachment.Id);
				}
				foreach(PollItem pollItem in pollItemAccessor.GetPollItemListByMessageId(id))
				{
					pollItemAccessor.Delete(pollItem.Id, id);
				}
				pollItemAccessor.DeleteVotersForPollMessage(id);

				foreach(Message message in GetReplies(id))
				{
					Delete(message.Id);
				}
				_messageTable.Rows.Remove(row);
				_messageTable.AcceptChanges();
			}
		}

		/// <summary>
		/// Insert a vote for a message
		/// </summary>
		/// <param name="id">Message id</param>
		/// <param name="profileId">Profile Id</param>
		/// <param name="point">Give a point to a message</param>
		public void InsertVote(int id, int profileId, int point)
		{
			_profile_x_pollMessage.InsertVoteForMessage(profileId, id, point);
		}

		/// <summary>
		/// Get list of votes that users rated for a message
		/// </summary>
		/// <param name="id">Message id</param>
		/// <returns>List of <see cref="Vote">Vote</see>s</returns>
		public ArrayList GetVoteList(int id)
		{
			return _profile_x_pollMessage.GetVoteListByMessageId(id);
		}
		#endregion

		private ArrayList GetMessageListByQuery(int pageNo, int numberPerPage, string query)
		{
			ArrayList messageList = new ArrayList();
			DataRow[] resultRows = _messageTable.Select(query);
	
			int startIndex = (pageNo == 0 || pageNo == 1)?0:numberPerPage * (pageNo - 1);
	
			for(int i=startIndex; i<resultRows.Length && i<startIndex + numberPerPage; i++)
			{
				messageList.Add(GetMessageFromResultRow(resultRows[i]));
			}
			return messageList;
		}

		private DataRow FindMessageDataRow(int id)
		{
			foreach(DataRow row in _messageTable.Rows)
			{
				if(DataConverter.GetInteger(row["Id"])==id)
					return row;
			}
			return null;
		}

		private Message GetMessageFromResultRow(DataRow row)
		{
			int messageOId = DataConverter.GetInteger(row["Id"]);
			MockCommentAccessor commentAccessor = MockCommentAccessor.Instance;
			MockAttachmentAccessor attachmentAccessor = MockAttachmentAccessor.Instance;
			MockPollItemAccessor pollItemAccessor = MockPollItemAccessor.Instance;

			if(Message.GetMessageType(DataConverter.GetInteger(row["MessageType"])) == MessageType.Message)
				return new Message(DataConverter.GetInteger(messageOId), DataConverter.GetInteger(row["No"]), DataConverter.GetString(row["Subject"]), DataConverter.GetString(row["Body"]), DataConverter.GetString(row["PostedByUserName"]), DataConverter.GetString(row["PostedByUserId"]), DataConverter.GetInteger(row["Hits"]), DataConverter.GetDateTime(row["CreateDate"]), MockProfileAccessor.Instance.Get(DataConverter.GetInteger(row["Author_Id"])), DataConverter.GetInteger(row["Board_Id"]), DataConverter.GetInteger(row["Club_Id"]), DataConverter.GetInteger(row["ReplyTo_Id"]), GetReplies(messageOId), commentAccessor.GetCommentListByMessageId(messageOId), attachmentAccessor.GetAttachmentListByMessageId(messageOId));
			else
				return new PollMessage(DataConverter.GetInteger(messageOId), DataConverter.GetInteger(row["No"]), DataConverter.GetString(row["Subject"]), DataConverter.GetString(row["Body"]), DataConverter.GetString(row["PostedByUserName"]), DataConverter.GetString(row["PostedByUserId"]), DataConverter.GetInteger(row["Hits"]), DataConverter.GetDateTime(row["CreateDate"]), MockProfileAccessor.Instance.Get(DataConverter.GetInteger(row["Author_Id"])), DataConverter.GetInteger(row["Board_Id"]), DataConverter.GetInteger(row["Club_Id"]), DataConverter.GetInteger(row["ReplyTo_Id"]), GetReplies(messageOId), commentAccessor.GetCommentListByMessageId(messageOId), attachmentAccessor.GetAttachmentListByMessageId(messageOId), pollItemAccessor.GetPollItemListByMessageId(messageOId), pollItemAccessor.GetVoterIdListByMessageId(messageOId));
		}
	}
}
